package com.dlc.shop.distribution.common.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.PhoneUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dlc.shop.bean.enums.UserBalanceLogType;
import com.dlc.shop.bean.event.allinpay.AllinpayBalanceUpdateEvent;
import com.dlc.shop.common.allinpay.constant.PaySysType;
import com.dlc.shop.common.bean.PaySettlementConfig;
import com.dlc.shop.common.config.Constant;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.util.Arith;
import com.dlc.shop.common.util.PageParam;
import com.dlc.shop.common.util.PrincipalUtil;
import com.dlc.shop.distribution.common.constants.DistributionUserIncomeStateEnum;
import com.dlc.shop.distribution.common.constants.DistributionUserIncomeTypeEnum;
import com.dlc.shop.distribution.common.dao.DistributionUserIncomeMapper;
import com.dlc.shop.distribution.common.dao.DistributionUserMapper;
import com.dlc.shop.distribution.common.dao.DistributionUserWalletMapper;
import com.dlc.shop.distribution.common.dto.DistributionOrderDto;
import com.dlc.shop.distribution.common.dto.DistributionUserIncomeDto;
import com.dlc.shop.distribution.common.dto.StatisticsDisUserIncomeDto;
import com.dlc.shop.distribution.common.model.DistributionUser;
import com.dlc.shop.distribution.common.model.DistributionUserIncome;
import com.dlc.shop.distribution.common.model.DistributionUserWallet;
import com.dlc.shop.distribution.common.model.DistributionUserWalletBill;
import com.dlc.shop.distribution.common.param.DistributionParam;
import com.dlc.shop.distribution.common.param.RangeTimeParam;
import com.dlc.shop.distribution.common.service.DistributionUserIncomeService;
import com.dlc.shop.distribution.common.service.DistributionUserWalletBillService;
import com.dlc.shop.distribution.common.vo.DistributionOrdersVO;
import com.dlc.shop.distribution.common.vo.DistributionSettleInfoVO;
import com.dlc.shop.service.SysConfigService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lgh on 2019/04/01.
 */
@Service
@RequiredArgsConstructor
public class DistributionUserIncomeServiceImpl extends ServiceImpl<DistributionUserIncomeMapper, DistributionUserIncome> implements DistributionUserIncomeService {

    private final DistributionUserIncomeMapper distributionUserIncomeMapper;
    private final DistributionUserMapper distributionUserMapper;

    private final DistributionUserWalletMapper distributionUserWalletMapper;
    private final ApplicationContext applicationContext;

    private final DistributionUserWalletBillService distributionUserWalletBillService;

    private final SysConfigService sysConfigService;


    @Override
    public IPage<DistributionUserIncome> incomeAndDistributionUserPage(Page page, Long shopId, RangeTimeParam rangeTimeParam, DistributionParam distributionParam, String orderNumber, Integer state, DistributionUserIncome distributionUserIncome) {
        Integer paySysType = this.getPaySysType();
        IPage<DistributionUserIncome> userPage = distributionUserIncomeMapper.incomeAndDistributionUserPage(page, shopId, rangeTimeParam, distributionParam, orderNumber, state, distributionUserIncome, paySysType);
        for (DistributionUserIncome record : userPage.getRecords()) {
            record.getDistributionUser().setUserMobile(PhoneUtil.hideBetween(record.getDistributionUser().getUserMobile()).toString());
            if (PrincipalUtil.isMobile(record.getDistributionUser().getNickName())) {
                record.getDistributionUser().setNickName(PhoneUtil.hideBetween(record.getDistributionUser().getNickName()).toString());
            }
        }
        return userPage;
    }

    @Override
    public IPage<DistributionOrderDto> getDistributionOrderDtoByDistributionUserId(Page page, Long distributionUserId) {
        Integer paySysType = this.getPaySysType();
        return distributionUserIncomeMapper.getDistributionOrderDtoByDistributionUserId(page, distributionUserId, paySysType);
    }

    @Override
    public StatisticsDisUserIncomeDto statisticsDistributionUserIncome(Long distributionUserId) {
        Integer paySysType = this.getPaySysType();
        StatisticsDisUserIncomeDto statisticsDisUserIncomeDto = new StatisticsDisUserIncomeDto();
        Date now = new Date();
        double todayAmount = distributionUserIncomeMapper.statisticsDisUserIncome(distributionUserId, DateUtil.beginOfDay(now), DateUtil.endOfDay(now), paySysType);
        double monthAmount = distributionUserIncomeMapper.statisticsDisUserIncome(distributionUserId, DateUtil.beginOfMonth(now), DateUtil.endOfMonth(now), paySysType);
        statisticsDisUserIncomeDto.setTodayAmount(todayAmount);
        statisticsDisUserIncomeDto.setMonthAmount(monthAmount);
        // 通联额外补充累计收益
        if (Objects.equals(paySysType, PaySysType.ALLINPAY.value())) {
            double addUpAmount = distributionUserIncomeMapper.statisticsDisUserIncome(distributionUserId, null, null, paySysType);
            statisticsDisUserIncomeDto.setAddUpAmount(addUpAmount);
        }
        return statisticsDisUserIncomeDto;
    }

    @Override
    public IPage<DistributionUserIncomeDto> getDistributionUserIncomePage(PageParam<DistributionUserIncome> page, Long distributionUserId) {
        Integer paySysType = this.getPaySysType();
        return distributionUserIncomeMapper.getDistributionUserIncomePage(page, distributionUserId, paySysType);
    }

    @Override
    public IPage<DistributionOrdersVO> getMyPromotionOrderByState(PageParam<DistributionOrdersVO> page, Long distributionUserId, Integer state) {
        Integer paySysType = this.getPaySysType();
        IPage<DistributionOrdersVO> promotionOrderPage = distributionUserIncomeMapper.getMyPromotionOrderByState(page, distributionUserId, state, paySysType);
        promotionOrderPage.getRecords().forEach(distributionOrdersVO -> distributionOrdersVO.setCommissionRate(Arith.div(distributionOrdersVO.getDistributionAmount(), distributionOrdersVO.getTotal(), 4)));
        return promotionOrderPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void commissionSettlementHandle(List<String> orderNumbers, Integer paySysType) {
        // 查询需要处理的支付收入记录,15天前确认收货的订单
        List<DistributionUserIncome> distributionUserIncomeList = distributionUserIncomeMapper.listWaitCommissionSettlement(orderNumbers,paySysType);
        if(CollectionUtils.isEmpty(distributionUserIncomeList)){
            return;
        }
        List<DistributionUserIncome> updateBatchDistributionUserIncomeList = new ArrayList<>();
        List<DistributionUserWalletBill> saveBatchDistributionWalletBillList = new ArrayList<>();
        Set<Long> userIdList = distributionUserIncomeList.stream().map(DistributionUserIncome::getDistributionUserId).collect(Collectors.toSet());
        List<DistributionUser> distributionUsers = distributionUserMapper.selectList(new LambdaQueryWrapper<DistributionUser>().in(DistributionUser::getDistributionUserId,userIdList));
        Map<Long, String> userMap = distributionUsers.stream().collect(Collectors.toMap(DistributionUser::getDistributionUserId, DistributionUser::getUserId));
        for (DistributionUserIncome distributionUserIncome : distributionUserIncomeList) {
            // 减少用户的待结算佣金，添加已结算金额
            DistributionUserWallet distributionUserWallet = distributionUserWalletMapper.selectById(distributionUserIncome.getWalletId());
            if (distributionUserWallet == null) {
                // 未找到分销员信息
                throw new YamiShopBindException("yami.distribution.exist.error");
            }
            if(!userMap.containsKey(distributionUserIncome.getDistributionUserId())){
                continue;
            }
            // 添加分销钱包日志
            // 如果当前还是普通结算环境，直接在分销员钱包添加金额
            if(Objects.equals(distributionUserIncome.getPaySysType(), PaySysType.DEFAULT.value())) {
                distributionUserWallet.setSettledAmount(Arith.add(distributionUserWallet.getSettledAmount(), distributionUserIncome.getIncomeAmount()));
                distributionUserWallet.setUnsettledAmount(Arith.sub(distributionUserWallet.getUnsettledAmount(), distributionUserIncome.getIncomeAmount()));
                distributionUserWallet.setAddupAmount(Arith.add(distributionUserWallet.getAddupAmount(), distributionUserIncome.getIncomeAmount()));
                distributionUserWalletMapper.updateById(distributionUserWallet);
                // 添加钱包变动日志
                if (Objects.equals(DistributionUserIncomeTypeEnum.AWARD_ONE.getValue(), distributionUserIncome.getIncomeType())) {
                    saveBatchDistributionWalletBillList.add(new DistributionUserWalletBill(distributionUserWallet, "直推奖励","Direct push reward", -distributionUserIncome.getIncomeAmount(), distributionUserIncome.getIncomeAmount(), 0.0, distributionUserIncome.getIncomeAmount(), 0));
                } else if (Objects.equals(DistributionUserIncomeTypeEnum.AWARD_TWO.getValue(), distributionUserIncome.getIncomeType())) {
                    saveBatchDistributionWalletBillList.add(new DistributionUserWalletBill(distributionUserWallet, "间推奖励","Indirect reward", -distributionUserIncome.getIncomeAmount(), distributionUserIncome.getIncomeAmount(), 0.0, distributionUserIncome.getIncomeAmount(), 0));
                } else {
                    saveBatchDistributionWalletBillList.add(new DistributionUserWalletBill(distributionUserWallet, "邀请奖励","Invitation reward", -distributionUserIncome.getIncomeAmount(), distributionUserIncome.getIncomeAmount(), 0.0, distributionUserIncome.getIncomeAmount(), 0));
                }
            }else{
                String userId = userMap.get(distributionUserIncome.getDistributionUserId());
//                UserExtension userExtension = new UserExtension();
//                userExtension.setUserId(userId);
//                userExtension.setAllinpayBalance(distributionUserIncome.getIncomeAmount());
//                userExtensionService.updateAllinpayBalanceByDistributionIncome(userExtension);
                // 通联余额变动
                AllinpayBalanceUpdateEvent event = new AllinpayBalanceUpdateEvent();
                event.setUserId(userId);
                event.setChangeBalance(distributionUserIncome.getIncomeAmount());
                event.setType(UserBalanceLogType.SETTLEMENT.value());
                event.setIsAddLog(true);
                event.setIsUpdateBalance(true);
                applicationContext.publishEvent(event);
            }
            // 更新收入状态
            updateBatchDistributionUserIncomeList.add(distributionUserIncome);
        }
        // 批量更新分销收入状态
        if (CollectionUtils.isNotEmpty(updateBatchDistributionUserIncomeList)) {
            updateBatchDistributionUserIncomeList.forEach( item -> {
                item.setState(DistributionUserIncomeStateEnum.COMMISSION.getValue());
            });
            if (updateBatchState(updateBatchDistributionUserIncomeList) <= 0){
                throw new YamiShopBindException("yami.distribution.batch.update.income");
            }
        }

        // 批量添加钱包变动日志
        if (CollectionUtils.isNotEmpty(saveBatchDistributionWalletBillList)) {
            distributionUserWalletBillService.saveBatch(saveBatchDistributionWalletBillList);
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public int updateBatchState(List<DistributionUserIncome> distributionUserIncomeList){
        int i = 0;
        for (DistributionUserIncome entity :
                distributionUserIncomeList) {
            int b = distributionUserIncomeMapper.updateById(entity);
            if (b > 0){
                i++;
            }
        }
        return i;
    }

    @Override
    public DistributionSettleInfoVO getSettleInfo(String userId) {
        Integer paySysType = this.getPaySysType();
        DistributionSettleInfoVO settleInfo = distributionUserMapper.getSettleInfo(userId, paySysType);
        if (Objects.isNull(settleInfo)) {
            settleInfo = new DistributionSettleInfoVO();
            settleInfo.setSettledAmount(0.0);
            settleInfo.setUnSettledAmount(0.0);
        }
        return settleInfo;
    }

    private Integer getPaySysType() {
        PaySettlementConfig config = sysConfigService.getSysConfigObject(Constant.PAY_SETTLEMENT_CONFIG, PaySettlementConfig.class);
        return config.getPaySettlementType();
    }
}
